package x.ovo.wechat.bot.impl.contact;

import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.cache.CacheUtil;
import org.dromara.hutool.core.cache.impl.TimedCache;
import org.dromara.hutool.core.collection.CollUtil;
import x.ovo.wechat.bot.core.Context;
import x.ovo.wechat.bot.core.contact.ContactManager;
import x.ovo.wechat.bot.core.contact.Contactable;
import x.ovo.wechat.bot.core.contact.RetrievalType;
import x.ovo.wechat.bot.core.entity.Contact;
import x.ovo.wechat.bot.core.entity.Member;
import x.ovo.wechat.bot.core.enums.ContactType;
import x.ovo.wechat.bot.core.http.WechatApi;
import x.ovo.wechat.bot.impl.config.ClientConfig;

import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j(topic = "ContactManager")
public enum DefaultContactManager implements ContactManager {
    INSTANCE;

    private final Context ctx = Context.INSTANCE;
    private final WechatApi api = ctx.getApi();
    /** 联系人缓存，默认30分钟过期，5分钟刷新 [username: Contact] */
    private final TimedCache<String, Contactable> contacts = CacheUtil.newTimedCache(Duration.ofMinutes(10).toMillis(), Duration.ofSeconds(10).toMillis());
    /** 群成员缓存，默认30分钟过期，5分钟刷新 [groupUsername: Collection<Member>] */
    private final TimedCache<String, Collection<Member>> groups = CacheUtil.newTimedCache(Duration.ofMinutes(30).toMillis(), Duration.ofMinutes(5).toMillis());

    @Override
    public void init() {
        new UserNameStrategy().init();
        new NickNameStrategy().init();
        new RemarkStrategy().init();
        ContactManager.super.init();
    }

    @Override
    public Contact get(String id) {
        return Optional.ofNullable(this.get(id, RetrievalType.USER_NAME))
                .orElseGet(() -> {
                    Contact contact = this.api.getContact(id);
                    this.contacts.put(contact.getUserName(), contact);
                    return contact;
                });
    }

    @Override
    public Contact get(String id, RetrievalType type) {
        // 先通过本地缓存获取，如果没有再通过api获取
        Contact contact = Optional.ofNullable((Contact) this.getStratrgy(type).get(this.contacts.iterator(), id))
                .orElseGet(() -> (Contact) this.getStratrgy(type).get(this.api.listContact().iterator(), id));
        // 联系人不为null，添加到缓存
        Optional.ofNullable(contact).ifPresent(c -> this.contacts.put(c.getUserName(), c));
        return contact;
    }

    @Override
    public void remove(String id) {
        this.remove(id, RetrievalType.USER_NAME);
    }

    @Override
    public void remove(String id, RetrievalType type) {
        this.getStratrgy(type).remove(this.contacts.iterator(), id);
    }


    @Override
    public void syncRecent(Collection<Contact> contacts) {
        if (CollUtil.isEmpty(contacts)) return;
        contacts.forEach(contact -> {
            contact.format();
            contact.getMemberList().forEach(Member::format);
            this.contacts.put(contact.getUserName(), contact);
        });
    }

    @Override
    public void flushContact() {
        Contact me = this.ctx.getSession().getContact();
        this.contacts.put(me.getUserName(), me);
        this.api.listContact().forEach(contact -> this.contacts.put(contact.getUserName(), contact));
        String owner = ClientConfig.get().getOwner();
        Contact contact = Optional.ofNullable(this.get(owner, RetrievalType.REMARK_NAME)).orElse(this.get(owner, RetrievalType.NICK_NAME));
        if (Objects.isNull(contact))
            log.warn("无法通过 [{}] 查找到联系人，bot管理员无法确定，请检查bot管理员的备注或昵称", owner);
        this.ctx.setMe(me);
        this.ctx.setOwner(contact);
        log.info("刷新联系人列表完成，共 {} 位联系人", this.contacts.size());
    }

    @Override
    public void flushGroup() {
        this.contacts.forEach(contact -> {
            if (ContactType.GROUP.equals(contact.getType())) {
                List<Member> members = this.api.listMember(contact.getUserName());
                this.groups.put(contact.getUserName(), members);
                log.info("已加载群 [{}] 共 {} 成员", contact.getNickName(), CollUtil.size(members));
            }
        });
    }

    @Override
    public Member get(String group, String id, RetrievalType type) {
        // 如果群成员缓存中不存在该群，则从微信服务器拉取群信息和群成员
        if (!this.groups.containsKey(group)) {
            this.get(group);
            List<Member> members = this.api.listMember(group);
            this.groups.put(group, members);
        }
        Member member = (Member) this.getStratrgy(type).get(this.groups.get(group).iterator(), id);
        // 如果member为空，需要刷新群组信息
        if (Objects.isNull(member)) {
            List<Member> members = this.api.listMember(group);
            this.groups.put(group, members);
            return (Member) this.getStratrgy(type).get(members.iterator(), id);
        }
        return member;
    }

    @Override
    public void remove(String group, String id, RetrievalType type) {
        if (!this.groups.containsKey(group)) return;
        this.getStratrgy(type).remove(this.groups.get(group).iterator(), id);
    }

}
